package calculation.base;

import java.util.Vector;

/**
 * 无标识，可以添加和移除课程，计算GPA
 *
 * 相较与第二版类图中的API有一点改变：
 *      使用getGPA返回GPA，而calculateGPA作为私有方法在必要时才被调用。
 *
 *增加了toString方法，将部分score类型从int改为double
 *
 *
 * TODO:
 * 1. 添加toString方法
 * 2. 添加计算单科GPA的方法
 * 3. 测试和调试
 *
 * @author xxx
 * @version 1.0.0
 */
public class Student {

    private Vector<Subject> subjects;
    private double GPA;
    private boolean GPA_need_update; // Lazy update
    private GPAIntervalTable gpa_interval_table;

    /**
     * GPA区间表：将分数转化为对应GPA
     *
     * 不想写一堆if-else，就添加了这个内部类
     */
    private class GPAIntervalTable {

        private int[] interval_vals;
        private double[] gpas;

        /**
         * 使用提供的临界值和对应gpa创建区间表
         * @param interval_vals 区间表中的所有临界值
         * @param gpas 对应的gpa
         */
        private GPAIntervalTable (int[] interval_vals, double[] gpas) throws IllegalArgumentException {
            if (interval_vals.length != gpas.length)
                throw new IllegalArgumentException("Length not equal: " +
                        interval_vals.length + " " + gpas.length);
            this.interval_vals = interval_vals;
            this.gpas = gpas;
        }

        /**
         * 使用四川大学的最新规定创建区间表
         */
        private GPAIntervalTable () {
            interval_vals = new int[]{90, 85, 80, 76, 73, 70, 66, 63, 61, 60};
            gpas = new double[]{4.0d, 3.7d, 3.3d, 3.0d, 2.7d, 2.3d, 2.0d, 1.7d, 1.3d, 1.0d};
        }

        /**
         * 将分数映射为GPA
         * @param score 要转化的分数.
         * @return 对应的GPA
         */
        double mapGPA(double score) {
            for (int i = 0; i < interval_vals.length; i++) {
                if (score >= interval_vals[i])
                    return gpas[i];
            }
            return 0.0d;
        }
    }

    /**
     * 创建一个无名、没有选课的学生
     */
    public Student() {
        GPA = 0.0d;
        GPA_need_update = true;
        subjects = new Vector<>();
        gpa_interval_table = new GPAIntervalTable();
    }

    /**
     * 添加科目
     * @param subject 要添加的科目
     */
    public void addSubject(Subject subject) throws IllegalArgumentException {
        if (subjects.contains(subject)) {
            throw new IllegalArgumentException("Already have subject: " + subject.toString());
        }
        subjects.add(subject);
        GPA_need_update = true;
    }

    /**
     * 移除科目
     * @param subject 要移除的科目
     */
    public void removeSubject(Subject subject) {
        subjects.remove(subject);
        GPA_need_update = true;
    }

    /**
     * 返回GPA
     * @return 该学生的GPA
     */
   public double getGPA() {
        if (GPA_need_update) {
            calculateGPA();
        }
        return GPA;
    }

    /**
     * 计算GPA
     */
    private void calculateGPA() {
        GPA = 0.0d;
        int sum_credit = 0;
        for (Subject s : subjects) {
            double score = s.getScore();
            int credit = s.getCredit();
            sum_credit += credit;
            GPA += gpa_interval_table.mapGPA(score) * credit;
        }
        GPA /= sum_credit;
        GPA_need_update = false;
    }
    
    /**
     * 返回分数列表
     */
    public String toString() {
    	String temp = "\n";
    	for (Subject s : subjects) {
    		temp += s.toString() + "\n";
    	}
    	return temp;
    }
}

